Visitor Pattern

Visitor pattern က behavioral design pattern တစ်ခု ပါ။ သူရဲ့ idea လေးက ရိုးရှင်းပါတယ်။ object တစ်ခုက အခြား object တွေ ဆီကို အလည်သွားခြင်းပါပဲ။

ဥပမာ Shape တွေကို area ရှာမည့် program တစ်ခု ရေးပါမယ်။

class Circle {
    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    double calculateArea() {
        return Math.PI * radius * radius;
    }
}

class Rectangle {
    double width;
    double height;

    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    double calculateArea() {
        return width * height;
    }
}

class Triangle {
    double base;
    double height;

    Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }

    double calculateArea() {
        return 0.5 * base * height;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle(5);
        Rectangle rectangle = new Rectangle(4, 6);
        Triangle triangle = new Triangle(3, 7);

        System.out.println("Circle area: " + circle.calculateArea());
        System.out.println("Rectangle area: " + rectangle.calculateArea());
        System.out.println("Triangle area: " + triangle.calculateArea());
    }
}

ဒီ code မှာ area တွက်ဖို့ class တိုင်းမှာ ထည့်ရေးထားရပါတယ်။ တနည်းပြောရင် Single Responbility မဟုတ်ပါဘူး။

calculateArea တွေက class တိုင်းမှာ ပါရမယ်ဆိုပြီး interface တစ်ခု ဆောက်လည်း ဖြစ်ပါတယ်။

အကယ်၍ visitor pattern ကို သုံးမယ် ဆိုရင် အခု လို ပြင်လို့ရပါတယ်။

Area Visitor က Shape တွေ ဆီ visit သွားပြီး area တွက်ပေးမယ့် သဘောပါ။ Java code ကို ကြည့်ရအောင်။

interface ShapeVisitor {
    double visit(Circle circle);
    double visit(Rectangle rectangle);
    double visit(Triangle triangle);
}

class AreaCalculator implements ShapeVisitor {
    @Override
    public double visit(Circle circle) {
        return Math.PI * circle.radius * circle.radius;
    }

    @Override
    public double visit(Rectangle rectangle) {
        return rectangle.width * rectangle.height;
    }

    @Override
    public double visit(Triangle triangle) {
        return 0.5 * triangle.base * triangle.height;
    }
}

interface Shape {
    double accept(ShapeVisitor visitor);
}

class Circle implements Shape {
    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double accept(ShapeVisitor visitor) {
        return visitor.visit(this);
    }
}

class Rectangle implements Shape {
    double width;
    double height;

    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double accept(ShapeVisitor visitor) {
        return visitor.visit(this);
    }
}

class Triangle implements Shape {
    double base;
    double height;

    Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }

    @Override
    public double accept(ShapeVisitor visitor) {
        return visitor.visit(this);
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle(5);
        Rectangle rectangle = new Rectangle(4, 6);
        Triangle triangle = new Triangle(3, 7);

        AreaCalculator areaCalculator = new AreaCalculator();

        System.out.println("Circle area: " + circle.accept(areaCalculator));
        System.out.println("Rectangle area: " + rectangle.accept(areaCalculator));
        System.out.println("Triangle area: " + triangle.accept(areaCalculator));
    }
}

အခု ဆိုရင် class က ပိုရိုးရှင်းသွားပြီး area calculation ကို သက်ဆိုင်ရာ AreaCalculator မှာပဲ လုပ်ပါတော့တယ်။ AreaCalculator က သက်ဆိုင်ရာ class ပေါ်မှာ မူတည်ပြီး အလုပ်လုပ်နိုင်အောင် visit ဆိုသည့် function ကို multiple လက်ခံအောင် လုပ်ထားပေးပါတယ်။

double visit(Circle circle);
double visit(Rectangle rectangle);
double visit(Triangle triangle);

Pros and Cons

Single Responsibility Principle ကို လိုက်နာ ထားပါတယ်။

Visitor object က complex structral တွေ ကို ရိုးရှင်းအောင် ပြောင်းလဲ အလုပ်လုပ်ပေးနိုင်ပါတယ်။

မကောင်းတာကတော့ လက်ရှိ class ထဲမှာ မပါသည့် class တစ်ခုကို visit လုပ်ချင်ရင် ထပ်ပြီး ဖြည့်ပေးရမှာ ဖြစ်ပြီး visitor class ကော ထပ်ဖြည့်မည့် class မှာပါ code ထပ်ဖြည့်ပေးရပါလိမ့်မယ်။